#define SEQAN_TRANSLATION_NO_PARALLEL
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <seqan/basic.h>
#include <seqan/file.h>
#include <seqan/sequence.h>
#include <seqan/translation.h>
#include <seqan/align.h>
#include <seqan/graph_align.h>
#include <seqan/graph_msa.h>
#include <seqan/graph_types.h>
#include <seqan/store.h>
#include <seqan/seq_io.h>
#include "gtest/gtest.h"
using namespace seqan;

typedef String<String<Dna> > DnaVec;
typedef String<AminoAcid> TSequence;


bool IsG(Dna const & d)
{
    return d == (Dna)'G';
}

bool IsC(Dna const & d)
{
    return d == (Dna)'C';
}

double GCContent(String<Dna> dna)
{
    int GC = 0;
    for(unsigned int i = 0; i < length(dna); ++i)
    {
        if(IsG(dna[i]) || IsC(dna[i]))
            GC++;
    }
    return (double)GC/(double)length(dna);
}

namespace {
    template <class T>
    std::string convertToString(T t)
    {
       std::stringstream ss;
       ss << t;
       std::string result = ss.str();
       return result;
    }

    std::string stringToAmino(std::string amString)
    {
        String<Rna> temp(amString);
        String<AminoAcid> aminoAcids;
        translate(aminoAcids, temp);
        return convertToString(aminoAcids);
    }

    bool allRowsAreTheSameButLast(Align<TSequence> align)
    {
        std::string initialString = convertToString(row(align, 0));
        for(unsigned i = 0; i < length(rows(align)) - 1; ++i)
        {
            if(initialString != convertToString(row(align, i)))
            {
                return false;
            }
        }
        return true;
    }

    TEST(GCContentTEST, GCtest)
    {
        EXPECT_EQ(1.0, GCContent(String<Dna>("CGCGGCGCGCGCG")));
        EXPECT_EQ(0, GCContent(String<Dna>("AATTATTATATATTA")));
        EXPECT_EQ(0.5, GCContent(String<Dna>("AGTCAGTCTGTGTG")));
    }

    TEST(RNATEST, RNATranscriptTest)
    {
       ASSERT_STREQ("AACCGG", convertToString(String<Rna>(String<Dna>("AACCGG"))).c_str());
       ASSERT_STREQ("AAUUAUU", convertToString(String<Rna>(String<Dna>("AATTATT"))).c_str());
       ASSERT_STREQ("ACUGACUG", convertToString(String<Rna>(String<Dna>("ACTGACTG"))).c_str());
    }

    TEST(AMINOTEST, AMINTranslateTest)
    {
       ASSERT_STREQ("KKKPPPGGF", stringToAmino("AAAAAAAAACCCCCCCCCGGGGGGUUU").c_str());
       ASSERT_STREQ("NVSIYYH", stringToAmino("AACGUUUCAAUCUACUAUCAU").c_str());
       ASSERT_STREQ("MNVS*", stringToAmino("AUGAACGUUUCAUGA").c_str());
    }

    TEST(MULTIPLY_ALIGNMENT, equalityTest)
    {
       Align<TSequence> align;
       resize(rows(align), 4);
       for(int i = 0; i < 3; ++i)
       {
         assignSource(row(align, i), TSequence("KKKPPPGGF"));
       }
       assignSource(row(align, 3), TSequence("KRKPPPGGF"));
       globalMsaAlignment(align, Blosum62(-1, -1));
       ASSERT_TRUE(allRowsAreTheSameButLast(align));
    }

    TEST(MULTIPLY_ALIGNMENT, expectedLengthTest)
    {
        Align<TSequence> align;
        resize(rows(align), 4);
        assignSource(row(align, 0), TSequence("KKKPPPGLGF"));
        assignSource(row(align, 1), TSequence("KPKKPPPGGF"));
        assignSource(row(align, 2), TSequence("KKKPPPGGF"));
        assignSource(row(align, 3), TSequence("KKKPPPGGF"));
        globalMsaAlignment(align, Blosum62(-1, -1));
        EXPECT_LT(9, length(row(align, 0)));
    }

}


void process(DnaVec dna)
{
    Align<TSequence> align;
    resize(rows(align), length(dna));
    typedef String<AminoAcid> TSequence;
    StringSet<TSequence> seq;

    for(unsigned i = 0; i < length(dna); ++i)
    {
        std::cout << "GC-content is " << GCContent(dna[i]) << std::endl;
        String<Rna> rna(dna[i]);
        std::cout << "RNA sequence: "<< std::endl;
        std::cout << rna << std::endl;
        String<AminoAcid> aSeqs;
        translate(aSeqs, dna[i]);
        std::cout << "Aminosequence: "<< std::endl;
        std::cout << aSeqs << std::endl;
        assignSource(row(align, i), aSeqs);
        appendValue(seq, aSeqs);
    }
    globalMsaAlignment(align, Blosum62(-1, -1));
    std::cout << "Multiply alignment: "<< std::endl;
    std::cout << align << std::endl;
    Graph<Alignment<StringSet<TSequence, Dependent<> > > > aliG(seq);
    globalMsaAlignment(aliG, Blosum62(-1, -1));
    std::ofstream out("./out.phy");
    out << length(rows(align)) << " " << sumOfPairsScore(aliG, Blosum62(-1, -1)) << std::endl;
    for(unsigned i = 0; i < length(rows(align)); ++i)
    {
        out << row(align, i) << std::endl;
    }
}

void usage()
{
    std::cerr << "Usage SSD [file_with_DNA_1.fasta file_with_DNA_2.gb ...]" << std::endl;
    std::cerr << "Closing application" << std::endl;

}

int main(int argc, char** argv)
{
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
    if(argc == 1)
    {
        usage();
        return 1;
    }
    DnaVec vec;
    for(int i = 0; i < argc - 1; ++i)
    {
        String<char> id;
        String<Dna> sequence;

        std::string filename = argv[i+1];
        std::ifstream in(filename.c_str());

        if(filename.substr(filename.length() - 3, 3) == ".gb")
        {
            read(in, sequence, Genbank());
        }
        else
        if(filename.substr(filename.length() - 6, 6) == ".fasta")
        {
            read(in, sequence, Fasta());
        }
        else
        {
            std::cout << "Wrong file" << std::endl;
            continue;
        }
        appendValue(vec, sequence);
        std::cout << sequence << std::endl;
    }
    process(vec);
    return 0;
}

